package com.nidu.demo.excel.listener;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.util.ListUtils;
import com.nidu.demo.dict.cache.DictCacheService;
import com.nidu.demo.dict.model.DictData;
import com.nidu.demo.excel.annotation.ExcelColumn;
import com.nidu.demo.i18n.util.I18nUtil;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import java.lang.reflect.Field;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Set;

/**
 * Excel数据验证监听器
 * 直接使用DictCacheService和I18nUtil，无需额外抽象
 *
 * @author nidu
 */
@Slf4j
@Getter
public class ExcelValidationListener<T> extends AnalysisEventListener<T> {

    private static final int BATCH_COUNT = 100;

    private List<T> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
    private final List<ExcelValidationError<T>> errorList = new ArrayList<>();

    private final Validator validator;
    private final DictCacheService dictCacheService;
    private final DataProcessor<T> dataProcessor;

    public ExcelValidationListener(Validator validator,
                                   DictCacheService dictCacheService,
                                   DataProcessor<T> dataProcessor) {
        this.validator = validator;
        this.dictCacheService = dictCacheService;
        this.dataProcessor = dataProcessor;
    }

    @Override
    public void invoke(T data, AnalysisContext context) {
        List<String> rowErrors = new ArrayList<>();

        try {
            // 处理每个字段
            for (Field field : data.getClass().getDeclaredFields()) {
                ExcelColumn column = field.getAnnotation(ExcelColumn.class);
                if (column == null) continue;

                field.setAccessible(true);
                Object value = field.get(data);

                // 获取列名（支持国际化）
                String columnName = getColumnDisplayName(column);

                try {
                    // 1. 必填校验
                    if (column.required() && (value == null || value.toString().trim().isEmpty())) {
                        rowErrors.add(getRequiredMessage(columnName));
                        continue;
                    }

                    // 如果值为空，跳过后续处理
                    if (value == null || value.toString().trim().isEmpty()) {
                        continue;
                    }

                    // 2. 字典值转换（导入时：标签转值）
                    if (!column.dictType().isEmpty()) {
                        String convertedValue = convertDictValue(column.dictType(),
                                value.toString(), columnName, rowErrors);
                        if (convertedValue != null) {
                            field.set(data, convertedValue);
                        }
                        continue;
                    }

                    // 3. 日期格式转换
                    if (value instanceof String && isDateField(field)) {
                        Object parsedDate = parseDateValue((String) value,
                                column.dateFormat(), field.getType(), columnName, rowErrors);
                        if (parsedDate != null) {
                            field.set(data, parsedDate);
                        }
                    }

                } catch (Exception e) {
                    log.error("处理字段{}时发生错误", field.getName(), e);
                    rowErrors.add(columnName + "处理失败: " + e.getMessage());
                }
            }

            // 4. JSR303验证
            if (validator != null && rowErrors.isEmpty()) {
                Set<ConstraintViolation<T>> violations = validator.validate(data);
                for (ConstraintViolation<T> violation : violations) {
                    rowErrors.add(violation.getPropertyPath() + ": " + violation.getMessage());
                }
            }

            // 如果有错误，记录错误信息
            if (!rowErrors.isEmpty()) {
                ExcelValidationError<T> error = new ExcelValidationError<>();
                error.setRowIndex(context.readRowHolder().getRowIndex() + 1);
                error.setData(data);
                error.setErrorMessages(rowErrors);
                errorList.add(error);

                log.warn("第{}行数据验证失败: {}", error.getRowIndex(), rowErrors);
                return;
            }

            // 验证通过，添加到缓存
            cachedDataList.add(data);

            // 达到批次大小，处理一批数据
            if (cachedDataList.size() >= BATCH_COUNT) {
                saveData();
                cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
            }

        } catch (Exception e) {
            log.error("处理Excel数据时发生异常", e);
            ExcelValidationError<T> error = new ExcelValidationError<>();
            error.setRowIndex(context.readRowHolder().getRowIndex() + 1);
            error.setData(data);
            error.setErrorMessages(Collections.singletonList("数据处理异常: " + e.getMessage()));
            errorList.add(error);
        }
    }

    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        saveData();
        log.info("Excel数据解析完成！成功处理{}条数据，失败{}条数据",
                getTotalSuccessCount(), errorList.size());
    }

    /**
     * 获取列显示名称（支持国际化）
     */
    private String getColumnDisplayName(ExcelColumn column) {
        if (cn.hutool.core.util.StrUtil.isNotBlank(column.i18nKey())) {
            return I18nUtil.getMessage(column.i18nKey(), column.value());
        }
        return column.value();
    }

    /**
     * 获取必填验证消息
     */
    private String getRequiredMessage(String columnName) {
        return I18nUtil.getMessage("excel.validation.required", new Object[]{columnName});
    }

    /**
     * 转换字典值（直接使用DictCacheService）
     */
    private String convertDictValue(String dictType, String label, String columnName, List<String> rowErrors) {
        if (dictCacheService == null) {
            log.warn("字典缓存服务未配置，跳过字典转换");
            return label;
        }

        try {
            // 检查字典类型是否存在
            List<DictData> dictList = dictCacheService.getDictList(dictType);
            if (dictList == null || dictList.isEmpty()) {
                rowErrors.add(getDictNotFoundMessage(dictType));
                return null;
            }

            // 标签转值（导入时）
            String value = dictList.stream()
                    .filter(dict -> label.equals(dict.getLabel()))
                    .map(DictData::getValue)
                    .findFirst()
                    .orElse(null);

            if (value == null) {
                // 转换失败，标签不存在
                rowErrors.add(getDictValueNotFoundMessage(label, dictType));
                return null;
            }

            return value;

        } catch (Exception e) {
            log.warn("字典值转换失败: dictType={}, label={}", dictType, label, e);
            rowErrors.add(columnName + "字典转换失败: " + e.getMessage());
            return null;
        }
    }

    /**
     * 获取字典类型不存在消息
     */
    private String getDictNotFoundMessage(String dictType) {
        return I18nUtil.getMessage("excel.validation.dict.not.found", new Object[]{dictType});
    }

    /**
     * 获取字典值不存在消息
     */
    private String getDictValueNotFoundMessage(String value, String dictType) {
        return I18nUtil.getMessage("excel.validation.dict.value.not.found",
                new Object[]{value, dictType});
    }

    /**
     * 解析日期值
     */
    private Object parseDateValue(String dateString, String format, Class<?> targetType,
                                  String columnName, List<String> rowErrors) {
        try {
            return parseDate(dateString, format, targetType);
        } catch (Exception e) {
            log.warn("日期解析失败: dateString={}, format={}", dateString, format, e);
            rowErrors.add(getDateFormatErrorMessage(columnName, format));
            return null;
        }
    }

    /**
     * 获取日期格式错误消息
     */
    private String getDateFormatErrorMessage(String columnName, String expectedFormat) {
        return I18nUtil.getMessage("excel.validation.date.format.error",
                new Object[]{columnName, expectedFormat});
    }

    /**
     * 判断是否为日期字段
     */
    private boolean isDateField(Field field) {
        return field.getType().equals(LocalDate.class) ||
                field.getType().equals(LocalDateTime.class) ||
                field.getType().equals(Date.class);
    }

    /**
     * 解析日期
     */
    private Object parseDate(String dateString, String format, Class<?> targetType) {
        if (dateString == null || dateString.trim().isEmpty()) {
            return null;
        }

        String trimmedDate = dateString.trim();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(format);

        if (targetType == LocalDate.class) {
            if (format.contains("HH:mm") && trimmedDate.length() >= 10) {
                return LocalDate.parse(trimmedDate.substring(0, 10),
                        DateTimeFormatter.ofPattern("yyyy-MM-dd"));
            }
            return LocalDate.parse(trimmedDate, formatter);
        } else if (targetType == LocalDateTime.class) {
            if (!format.contains("HH:mm")) {
                return LocalDateTime.parse(trimmedDate + " 00:00:00",
                        DateTimeFormatter.ofPattern(format + " HH:mm:ss"));
            }
            return LocalDateTime.parse(trimmedDate, formatter);
        } else if (targetType == Date.class) {
            LocalDateTime localDateTime;
            if (!format.contains("HH:mm")) {
                localDateTime = LocalDateTime.parse(trimmedDate + " 00:00:00",
                        DateTimeFormatter.ofPattern(format + " HH:mm:ss"));
            } else {
                localDateTime = LocalDateTime.parse(trimmedDate, formatter);
            }
            return java.sql.Timestamp.valueOf(localDateTime);
        }

        throw new IllegalArgumentException("不支持的日期类型: " + targetType);
    }

    /**
     * 保存数据
     */
    private void saveData() {
        if (dataProcessor != null && !cachedDataList.isEmpty()) {
            dataProcessor.process(cachedDataList);
        }
    }

    /**
     * 获取成功处理的数据总数
     */
    public int getTotalSuccessCount() {
        return cachedDataList.size(); // 这里需要根据实际业务逻辑调整
    }

    /**
     * 获取所有成功的数据
     */
    public List<T> getDataList() {
        return new ArrayList<>(cachedDataList);
    }

    /**
     * 数据处理器接口
     */
    public interface DataProcessor<T> {
        void process(List<T> dataList);
    }

    /**
     * Excel验证错误信息
     */
    @lombok.Data
    public static class ExcelValidationError<T> {
        private int rowIndex;
        private T data;
        private List<String> errorMessages;
    }
}